#region Using

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Configuration.Provider;
using BlogEngine.Core;

#endregion

namespace BlogEngine.Core.Providers
{
	/// <summary>
	/// A base class for all custom providers to inherit from.
	/// </summary>
    public abstract class BlogProvider : ProviderBase
	{
		#region Posts

		/// <summary>
		/// Retrieves a Post from the provider based on the specified id.
		/// </summary>
		/// <param name="id">The id.</param>
		/// <returns></returns>
        public abstract Post SelectPost(int id);

		/// <summary>
		/// Counts the posts.
		/// </summary>
		/// <returns></returns>
		public abstract long CountPosts();

		/// <summary>
		/// Retrieves a Post from the provider based on the specified id.
		/// </summary>
		/// <param name="permalink">The permalink.</param>
		/// <returns></returns>
		public abstract Post SelectPost(string permalink);

		/// <summary>
		/// Selects the next post.
		/// </summary>
		/// <param name="id">The id.</param>
		/// <returns></returns>
		public abstract Post SelectNextPost(int id);

		/// <summary>
		/// Selects the previous post.
		/// </summary>
		/// <param name="id">The id.</param>
		/// <returns></returns>
		public abstract Post SelectPreviousPost(int id);

		/// <summary>
		/// Selects the posts by term.
		/// </summary>
		/// <param name="type">The type.</param>
		/// <param name="slug">The slug.</param>
		/// <param name="startIndex">The start index.</param>
		/// <param name="count">The count.</param>
		/// <returns></returns>
		public abstract List<Post> SelectPostsByTerm(TermType type, string slug, int startIndex, int count);

		/// <summary>
		/// Selects the post by author.
		/// </summary>
		/// <param name="author">The author.</param>
		/// <param name="startIndex">The start index.</param>
		/// <param name="count">The count.</param>
		/// <returns></returns>
		public abstract List<Post> SelectPostsByAuthor(string author, int startIndex, int count);

		/// <summary>
		/// Selects the post by date.
		/// </summary>
		/// <param name="dateFrom">The date from.</param>
		/// <param name="dateTo">The date to.</param>
		/// <param name="startIndex">The start index.</param>
		/// <param name="count">The count.</param>
		/// <returns></returns>
		public abstract List<Post> SelectPostsByDate(DateTime dateFrom, DateTime dateTo, int startIndex, int count);

		/// <summary>
		/// Retrieves all Posts from the provider and returns them in a List.
		/// </summary>
		/// <param name="startIndex">The start index.</param>
		/// <param name="count">The count.</param>
		/// <returns></returns>
		public abstract List<Post> SelectPosts(int startIndex, int count);

		/// <summary>
		/// Inserts a new Post into the data store specified by the provider.
		/// </summary>
		/// <param name="post">The post.</param>
        public abstract void InsertPost(Post post);

		/// <summary>
		/// Updates an existing Post in the data store specified by the provider.
		/// </summary>
		/// <param name="post">The post.</param>
        public abstract void UpdatePost(Post post);

		/// <summary>
		/// Deletes a Post from the data store specified by the provider.
		/// </summary>
		/// <param name="post">The post.</param>
        public abstract void DeletePost(Post post);

		#endregion

		#region Comments

		/// <summary>
		/// Selects the comment.
		/// </summary>
		/// <param name="id">The id.</param>
		/// <returns></returns>
		public abstract Comment SelectComment(int id);

		/// <summary>
		/// Selects the comments by post.
		/// </summary>
		/// <param name="postId">The post id.</param>
		/// <returns></returns>
		public abstract List<Comment> SelectCommentsByPost(int postId);

		/// <summary>
		/// Inserts the comment.
		/// </summary>
		/// <param name="comment">The comment.</param>
		public abstract void InsertComment(Comment comment);

		/// <summary>
		/// Updates the comment.
		/// </summary>
		/// <param name="comment">The comment.</param>
		public abstract void UpdateComment(Comment comment);

		/// <summary>
		/// Deletes the comment.
		/// </summary>
		/// <param name="comment">The comment.</param>
		public abstract void DeleteComment(Comment comment);

		/// <summary>
		/// Changes all comment status by post.
		/// </summary>
		/// <param name="postId">The post id.</param>
		/// <param name="fromStatus">From status.</param>
		/// <param name="toStatus">To status.</param>
		public abstract void ChangeAllCommentStatusByPost(int postId, CommentStatus fromStatus, CommentStatus toStatus);

		#endregion

		#region Attachments

		/// <summary>
		/// Selects the attachment.
		/// </summary>
		/// <param name="id">The id.</param>
		/// <returns></returns>
		public abstract Attachment SelectAttachment(int id);

		/// <summary>
		/// Selects the attachment by post.
		/// </summary>
		/// <param name="startIndex">The start index.</param>
		/// <param name="count">The count.</param>
		/// <returns></returns>
		public abstract List<Attachment> SelectAttachments(int startIndex, int count);

		/// <summary>
		/// Counts the attachments.
		/// </summary>
		/// <returns></returns>
		public abstract long CountAttachments();

		/// <summary>
		/// Inserts the attachment.
		/// </summary>
		/// <param name="attachment">The attachment.</param>
		public abstract void InsertAttachment(Attachment attachment);

		/// <summary>
		/// Updates the attachment.
		/// </summary>
		/// <param name="attachment">The attachment.</param>
		public abstract void UpdateAttachment(Attachment attachment);

		/// <summary>
		/// Deletes the attachment.
		/// </summary>
		/// <param name="attachment">The attachment.</param>
		public abstract void DeleteAttachment(Attachment attachment);

		#endregion

		#region Page

		/// <summary>
		/// Selects the pages.
		/// </summary>
		/// <returns></returns>
		public abstract List<Page> SelectPages();

		/// <summary>
		/// Retrieves a Post from the provider based on the specified id.
		/// </summary>
		/// <param name="id">The id.</param>
		/// <returns></returns>
		public abstract Page SelectPage(int id);

		/// <summary>
		/// Retrieves a Post from the provider based on the specified id.
		/// </summary>
		/// <param name="permalink">The permalink.</param>
		/// <returns></returns>
		public abstract Page SelectPage(string permalink);

		/// <summary>
		/// Inserts a new Post into the data store specified by the provider.
		/// </summary>
		/// <param name="post">The post.</param>
		public abstract void InsertPage(Page post);

		/// <summary>
		/// Updates an existing Post in the data store specified by the provider.
		/// </summary>
		/// <param name="post">The post.</param>
		public abstract void UpdatePage(Page post);

		/// <summary>
		/// Deletes a Post from the data store specified by the provider.
		/// </summary>
		/// <param name="post">The post.</param>
		public abstract void DeletePage(Page post);

		#endregion

		#region Terms

		/// <summary>
		/// Selects the term.
		/// </summary>
		/// <param name="type">The type.</param>
		/// <param name="slug">The slug.</param>
		/// <returns></returns>
		public abstract Term SelectTerm(TermType type, string slug);

		/// <summary>
		/// Selects the terms.
		/// </summary>
		/// <returns></returns>
		public abstract List<Term> SelectTerms();

		/// <summary>
		/// Selects the terms by post.
		/// </summary>
		/// <param name="postId">The post id.</param>
		/// <returns></returns>
		public abstract List<Term> SelectTermsByPost(int postId);

		#endregion

		#region Settings

		/// <summary>
		/// Loads the settings from the provider.
		/// </summary>
		/// <returns></returns>
        public abstract Dictionary<string, string> LoadSettings();

		/// <summary>
		/// Saves the settings to the provider.
		/// </summary>
		/// <param name="settings">The settings.</param>
		public abstract void SaveSettings(Dictionary<string, string> settings);

		#endregion
	}

    /// <summary>
    /// A collection of all registered providers.
    /// </summary>
    public class BlogProviderCollection : ProviderCollection
    {
        /// <summary>
        /// Gets a provider by its name.
        /// </summary>
        public new BlogProvider this[string name]
        {
            get { return (BlogProvider)base[name]; }
        }

        /// <summary>
        /// Add a provider to the collection.
        /// </summary>
        public override void Add(ProviderBase provider)
        {
            if (provider == null)
                throw new ArgumentNullException("provider");

            if (!(provider is BlogProvider))
                throw new ArgumentException
                    ("Invalid provider type", "provider");

            base.Add(provider);
        }
    }

}
